package com.andy.basics;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;

@Component
public class Utils {

	private static final String CLASS = Utils.class.getName();

	private static final Logger DEBUG = Logger.getLogger(Constants.DEBUG_KEY + Utils.CLASS);

	public static final int DAY_IN_MILLISECOND = 1000 * 3600 * 24;

	public static final int BUFFER_LENGTH = 1024;

	private MessageSource messageSource;

	public byte[] readBytes(final File file) {

		try {
			FileInputStream fis = new FileInputStream(file);
			byte[] data = new byte[(int) file.length()];

			int offset = 0;

			while (true) {

				int len = data.length - offset;

				if (len == 0) {
					break;
				}

				if (len > Utils.BUFFER_LENGTH) {
					len = Utils.BUFFER_LENGTH;
				}

				int n = fis.read(data, offset, len);
				if (n == -1) {
					break;
				}
				offset = offset + n;
			}
			fis.close();
			return data;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/*
	 * public void copyBytes(InputStream is, OutputStream os) throws IOException
	 * { copyBytes(is, os, BUFFER_LENGTH); }
	 * 
	 * public void copyBytes(InputStream is, OutputStream os, int bufferLength)
	 * throws IOException {
	 * 
	 * byte[] buf = new byte[bufferLength]; int count = 0;
	 * 
	 * while ((count = is.read(buf)) >= 0) { os.write(buf, 0, count); } }
	 */

	public BufferedImage createImage(final String data, final int width, final int height, final String rowSeparator,
			final String columnSeparator) {
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		String rowData[] = data.split(rowSeparator);

		for (int row = 0; row < height; row++) {
			String colData[] = rowData[row].split(columnSeparator);
			for (int col = 0; col < width; col++) {
				image.setRGB(col, row, Integer.parseInt(colData[col]));
			}
		}
		return image;
	}

	public File saveImageInTempFile(final BufferedImage image, final String imageType) throws IOException, FileNotFoundException {
		File file = File.createTempFile("image", null);
		FileOutputStream ff = new FileOutputStream(file);
		ImageIO.write(image, imageType, ff);
		ff.close();
		return file;
	}

	public Throwable getRootCause(final Throwable throwable) {
		if (throwable.getCause() == null) {
			return throwable;
		}
		return this.getRootCause(throwable.getCause());
	}

	public String normalizeHtml(final String input) {
		return input.replaceAll("'", "").replaceAll("\"", "");
	}

	public String fetchExceptionDetails(final Exception e) {
		if (e instanceof SQLException) {
			SQLException s = (SQLException) e;
			s.getMessage();
		}

		return null;
	}

	public int largest(final int... numbers) {
		int largest = numbers[0];
		for (int x : numbers) {
			if (x > largest) {
				largest = x;
			}
		}
		return largest;
	}

	public int findDifferenceInDays(final Date startDate, final Date endDate) {
		return (int) (((endDate.getTime() - startDate.getTime()) / Utils.DAY_IN_MILLISECOND) + (((endDate.getTime() - startDate
				.getTime()) % Utils.DAY_IN_MILLISECOND) == 0 ? 0 : 1));
	}

	public StringBuilder createCommaSeparatedIDs(final List<? extends Entity> entities, final StringBuilder buffer) {
		for (int i = 0; i < entities.size(); i++) {
			buffer.append(entities.get(i).getId());
			if (i < entities.size() - 1) {
				buffer.append(',');
			}
		}
		return buffer;
	}

	public Object getPublicAttribute(final Object object, final String name) throws Exception {
		if (!name.contains(".")) {
			try {
				Utils.DEBUG.debug("Finding 'get' method for object of class " + object.getClass().getName() + ", for attribute "
						+ name);
				return object.getClass().getMethod(this.createGetter(name), null).invoke(object, null);
			} catch (NoSuchMethodException e) {
				Utils.DEBUG.debug("Get method could not be found, finding 'is' method for object of class "
						+ object.getClass().getName() + ", for attribute " + name + ", Error is " + e.getMessage());
				return object.getClass().getMethod(this.createBooleanGetter(name), null).invoke(object, null);
			}
		}
		Utils.DEBUG.debug("Finding get method for object of class " + object.getClass().getName() + ", for attribute " + name
				+ " by deep recursion");
		return this.getPublicAttribute(this.getAttribute(object, name.substring(0, name.indexOf('.'))),
				name.substring(name.indexOf('.') + 1));
	}

	public Object getAttribute(final Object object, final String name) throws Exception {
		if (!name.contains(".")) {
			try {
				Utils.DEBUG.debug("Finding 'get' method for object of class " + object.getClass().getName() + ", for attribute "
						+ name);
				return object.getClass().getDeclaredMethod(this.createGetter(name), null).invoke(object, null);
			} catch (NoSuchMethodException e) {
				Utils.DEBUG.debug("Get method could not be found, finding 'is' method for object of class "
						+ object.getClass().getName() + ", for attribute " + name + ", Error is " + e.getMessage());
				return object.getClass().getDeclaredMethod(this.createBooleanGetter(name), null).invoke(object, null);
			}
		}
		Utils.DEBUG.debug("Finding get method for object of class " + object.getClass().getName() + ", for attribute " + name
				+ " by deep recursion");
		return this.getAttribute(this.getAttribute(object, name.substring(0, name.indexOf('.'))),
				name.substring(name.indexOf('.') + 1));
	}

	public String createGetter(final String name) {
		String getter = "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
		Utils.DEBUG.debug("Getter created for " + name + " as " + getter);
		return getter;
	}

	public String createBooleanGetter(final String name) {
		return "is" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
	}

	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}

	public String getMessage(String key) {
		return this.messageSource.getMessage(key, null, Locale.ENGLISH);
	}

	public String getToday() {
		return new SimpleDateFormat("dd/MM/yyyy").format(new Date());
	}

}
